//
//  TestMode..cpp
//  sad
//
//  Created by Christopher Kemsley on 4/6/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include "ModuleFactory.hpp"
#include "SystemCDefinitions.hpp"
#include "FiFoBuffer.hpp"
#include "Log.hpp"

/** This is an example **/





struct	ModelWrapper1x1Settings : public Settings
{
	std::string	inputName ;
	std::string	outputName ;
	std::string	clockName ;
	std::string	resetName ;
	
	
	ModelWrapper1x1Settings	( std::string const & name )
	:	Settings ( name )
	{
	add ( "inputName" , inputName ) ;
	add ( "outputName" , outputName ) ;
	add ( "resetName", resetName) ;
	add ( "clockName", clockName) ;
	}
	
	
	virtual void		validate () // called from codec
		{
		if ( inputName.size() == 0 )
			ThrowException ( "ModelWrapper1x1Settings" , "Input name has zero-length" , __FILE__,__LINE__ ) ;
		if ( outputName.size() == 0 )
			ThrowException ( "ModelWrapper1x1Settings" , "Output name has zero-length" , __FILE__,__LINE__ ) ;
		if ( resetName.size() == 0 )
			ThrowException ( "ModelWrapper1x1Settings" , "Reset name has zero-length" , __FILE__,__LINE__ ) ;
		if ( clockName.size() == 0 )
			ThrowException ( "ModelWrapper1x1Settings" , "Clock name has zero-length" , __FILE__,__LINE__ ) ;
		}
} ;




template <class Type>
class	ModelWrapper1x1 : public ConfiguredModel<ModelWrapper1x1Settings>
{
public:
	
	Type rtl;
	
	sc_event readEvent, writeEvent;
	
	sc_in<bool>		mClockInput ;
	sc_in<sc_logic> mResetInput ;
	
	sc_port<FiFo::ReadInterface>	mpInput1 ;
	sc_port<FiFo::WriteInterface>	mpOutput1 ;
	
	//signals
	sc_signal<sc_lv<32> > 	inputData;
	sc_signal<sc_logic> 	inputFifoIsEmpty; 
	sc_signal<sc_logic> 	outputFifoIsFull;
	sc_signal<bool> 	clockSignal;
	sc_signal<sc_logic>	 resetSignal;
	sc_signal<sc_logic> 	startSignal;//must use a signal to assign it to the model, this will always be SC_LOGIC_1
	
	//outputs
	sc_signal<sc_lv<32> > 	outputData;
	sc_signal<sc_logic>	doneProcessingBlock;
	sc_signal<sc_logic> 	taskIsIdle;
	sc_signal<sc_logic> 	readingInput;
	sc_signal<sc_logic> 	writingOutput;
	
	unsigned temp_read_buffer0;
	unsigned temp_read_buffer1;
	
	SC_HAS_PROCESS(ModelWrapper1x1);
	
	ModelWrapper1x1 ( ModelVariant const & identity )
	:	ConfiguredModel<ModelWrapper1x1Settings>	( identity )
	,	mpInput1	( )
	,	mpOutput1	( )
	,	rtl			(sc_module_name(( identity.instanceName+"_model" ).c_str()))
		{
		
		
		//Log::states("ModelWrapper1x1") <<"creating model wrapper 1x1\n";
		
		// Bind our read/write ports
		bindPortToInterfaceNamed ( mpInput1 , mConfig.inputName ) ;
		bindPortToInterfaceNamed ( mpOutput1 , mConfig.outputName ) ;
		
		
		// Bind our clock/reset input lines
		bindInputToSignalNamed ( mClockInput , mConfig.clockName ) ;
		bindInputToSignalNamed ( mResetInput , mConfig.resetName ) ;
		
		
		//initialize input logic vectors
		inputData.write(0);
		inputFifoIsEmpty.write(SC_LOGIC_0);
		outputFifoIsFull.write(SC_LOGIC_0);
		startSignal = SC_LOGIC_1;
		
		
		//rtl input signals
		bindInputToSignalNamed ( rtl.ap_clk , mConfig.clockName ) ;
		bindInputToSignalNamed ( rtl.ap_rst , mConfig.resetName ) ;
		rtl.ap_start(startSignal) ;
		rtl.in_r_dout(inputData) ;
		rtl.in_r_empty_n(inputFifoIsEmpty) ;
		rtl.out_r_full_n(outputFifoIsFull) ;
		
		
		//rtl output signals
		rtl.ap_done( doneProcessingBlock ) ;
		rtl.ap_idle( taskIsIdle ) ;
		rtl.in_r_read( readingInput ) ;
		rtl.out_r_din(outputData) ;
		rtl.out_r_write( writingOutput );
		

		
		SC_THREAD(readDataIn);
		SC_THREAD(writeDataOut);
		
		SC_METHOD(moveDataEvents);
		sensitive << mClockInput.posedge_event();
		sensitive << mResetInput.posedge_event();
		
		sc_trace_file* mVcdModelFile = sc_create_vcd_trace_file(sc_module_name(( identity.instanceName+"_model" ).c_str()));
		 
		 sc_trace(mVcdModelFile, inputData, "inputData");
		 sc_trace(mVcdModelFile, inputFifoIsEmpty, "inputFifoIsEmpty");
		 sc_trace(mVcdModelFile, outputFifoIsFull, "outputFifoIsFull");
		 sc_trace(mVcdModelFile, startSignal, "startSignal");
		 sc_trace(mVcdModelFile, outputData, "outputData");
		 sc_trace(mVcdModelFile, doneProcessingBlock, "doneProcessingBlock");
		 sc_trace(mVcdModelFile, readingInput, "readingInput");
		 sc_trace(mVcdModelFile, writingOutput, "writingOutput");
		 
		
		}
		


	void moveDataEvents( void )
	{
		//only signal data moving events if reset is low.

			if(readingInput.read() == SC_LOGIC_1)
				readEvent.notify();
			
			if(writingOutput.read() == SC_LOGIC_1)
				writeEvent.notify();
	
				//update the inputFifo state
			if(mpInput1->availableLength() == 0)
				{
			
			//	Log::states("ModelWrapper1x1") <<"updating input fifo state\n" ;
			
				inputFifoIsEmpty.write( SC_LOGIC_0 );
				}
		
			else 
				{
				
			//	Log::states("ModelWrapper1x1") <<"updating output fifo state\n" ;
			
				inputFifoIsEmpty.write(SC_LOGIC_1);
				}

			//update the output fifo state
			if(mpOutput1->availableCapacity() == 0)
				{
				outputFifoIsFull.write(SC_LOGIC_0);
				}
			else
				{
				outputFifoIsFull.write(SC_LOGIC_1);
				}

	}
	
	
	void readDataIn( void )
	{
	  
		//buffer some data to deal with fifo delay
		temp_read_buffer0 = mpInput1->read();
		inputData.write(temp_read_buffer0);
		//temp_read_buffer0 = mpInput1->read();
	  
		while(1)
		{
		  

		  
		  
			wait(readEvent);
	
			
			//if the read input signal is high, then it will read the value on input data,
			//we first update inputData by reading from the fifo
	
			//Log::states("ModelWrapper1x1") <<"reading input\n" ;
			
			//std::cout<<"reading input\n";
			temp_read_buffer0 = mpInput1->read();		
			inputData.write(temp_read_buffer0); //FIXME : I cast the word to unsigned, does WORD cast to unsigned?
			
		}
		
	}
		
	void writeDataOut( void )
	{
		while(1){
		
			//if write is high, we should grab the data that is at the output

			wait(writeEvent);
			
			//Log::states("ModelWrapper1x1") <<"writing output\n" ;
			
			//std::cout<<"writing output\n";
			
			mpOutput1->write(outputData.read().to_uint());
			
		
		
		}
		
	}
	
	
	
};



